import {
    Territory,
    Bucket,
    Common,
    Authorize,
    File, defaultConfig
} from "cess-js-sdk-frontend";
import { formatBalance, formatBalanceStr } from "../utils/formatter";
import * as oss from "./oss";
import * as evm from "./evm";
import * as graphql from "./graphql";
import * as fileUpload from "./file-upload";
import moment from "moment";
import store from "../utils/store";
import * as valitor from "../utils/valitor";
import { notiOK, notiError, alertError, alertOk, confirm, loading } from "../utils/antd-helper";
import * as antdHelper from "../utils/antd-helper";
import webconfig from "../webconfig";
import { sleep, getProxyAuthorizeMessage } from "../utils/common";
const bs58 = require("bs58");


export {
    territories,//----------------territory
    territoryExtendTime,//----------------territory
    territoryExtendSize,//----------------territory
    territoryCreat,//----------------territory
    territoryRename,//----------------territory
    territoryReactivate,//----------------territory
    territoryRefresh,//----------------territory
    authorize,
    getContainer,
    getContainerTree,
    newContainer,
    renameContainer,
    deleteContainers,
    fileMove,
    fileDeletes,
    fileDetail,
    fileSearch
}
function getAccountType() {
    return store.get("accountType") || "wallet";
}
function alertRet(ret, okMsg) {
    if (!ret.msg) {
        ret.msg = 'ok';
    }
    if (ret.msg != 'ok') {
        alertError(ret.msg);
    }
    else if (okMsg) {
        alertOk(okMsg);
    }
    return ret;
}
async function commonAction(funName, okMsg, ...params) {
    let ret = '';
    try {
        let type = getAccountType();
        let obj = type == 'email' ? graphql : type == 'evm' ? evm : oss;
        ret = await obj[funName](...params);
    } catch (e) {
        ret = { msg: e.message || e };
    } finally {
        return alertRet(ret, okMsg);
    }
}
async function commonActionForTerritory(funName, okMsg, ...params) {
    let ret = '';
    try {
        let type = getAccountType();
        if (type == 'email') {
            ret = await graphql[funName](...params);
        } else {
            let obj = type == 'evm' ? evm : oss;
            ret = await obj[funName](...params);
            if (ret.msg == 'ok') {
                ret = await graphql[funName](params[0]);
            }
        }
    } catch (e) {
        ret = { msg: e.message || e };
    } finally {
        return alertRet(ret, okMsg);
    }
}

//territory
async function territories() {
    let ret = '';
    try {
        ret = await oss.territories();
        if (ret.msg == 'ok' && ret.data && ret.data.length) {
            ret.data.sort((t1, t2) => t1.deadline - t2.deadline);
        }
    } catch (e) {
        ret = { msg: e.message || e };
    } finally {
        return alertRet(ret);
    }
}
async function territoryCreat(territoryName, gibCount, days) {
    let ret = '';
    let funName = "territoryCreat";
    try {
        let type = getAccountType();
        if (type == 'email') {
            ret = await graphql[funName](...arguments);
            return ret;
        }
        let obj = type == 'evm' ? evm : oss;
        ret = await obj[funName](...arguments);
        if (ret.msg != 'ok') {
            return ret;
        }
        let list = await territories();
        if (list.msg != 'ok') {
            return list;
        }
        let tmp = list.data.find(t => t.name == territoryName);
        if (tmp && tmp.key) {
            if (type == 'evm') {
                console.log('waiting...');
                await sleep(5000);
            }
            ret = await graphql[funName](...arguments, tmp.key);
        }
    } catch (e) {
        console.log(e);
        ret = { msg: e.message || e };
    } finally {
        return alertRet(ret, "Transcation successfuly");
    }


}
async function territoryExtendSize(territoryName, gibCount) {
    return await commonActionForTerritory("territoryExtendSize", "Transcation successfuly", ...arguments);
}
async function territoryExtendTime(territoryName, days) {
    let ret = await commonActionForTerritory("territoryExtendTime", "Transcation successfuly", ...arguments);
    return ret;
}
async function territoryReactivate(territoryName, days) {
    let ret = await commonActionForTerritory("territoryReactivate", "Transcation successfuly", ...arguments);
    return ret;
}
async function territoryRename(oldName, newName) {
    let ret = await commonAction("territoryRename", "Transcation successfuly", ...arguments);
    if (ret.msg == 'ok') {
        let type = getAccountType();
        if (type != 'email') {
            ret = await graphql.territoryRename(...arguments);
        }
    }
    return ret;
}
async function territoryRefresh(notNoti) {
    let ret = await graphql.territoryRefresh();
    if (ret.msg != 'ok') {
        antdHelper.alertError(ret.msg);
        return ret;
    }
    let c1 = ret.data.refreshTerritory;
    ret = await graphql.fileMapRefresh();
    if (ret.msg != 'ok') {
        antdHelper.alertError(ret.msg);
        return ret;
    }
    if (notNoti) {
        return ret;
    }
    let c2 = ret.data.refreshFileMap;
    antdHelper.msgOK(`Synchronized. Added ${c1} territories and ${c2} files`);
    return ret;
}

//authorize
async function authorize() {
    let type = getAccountType();
    let ret = '';
    try {
        if (type == 'email') {
            ret = await graphql.authorize();
        } else {
            await oss.init();
            let blockHeight = await oss.queryBlockHeight();
            let message = getProxyAuthorizeMessage(webconfig.gatewayAddr, blockHeight);
            let signMsg = "";
            if (type == 'evm') {
                signMsg = await evm.signMsg(message);
                signMsg=signMsg.replace("0x","");
            } else {
                let account = oss.getAccount();
                signMsg = await oss.signMessage(account.address, message);
            }
            console.log("message", message);
            ret = await graphql.authorizeForWallet(signMsg, blockHeight);
        }
    } catch (e) {
        console.log(e);
        ret = { msg: e.message || e };
    } finally {
        return alertRet(ret, "Authorzed");
    }
}

//Container
async function getContainer(parentId, currTerritoryId, setDirs, setIsLoading) {
    let list = [], ret;
    try {
        setIsLoading(true);
        ret = await graphql.getContainer(parentId, currTerritoryId);
        console.log({ ret });
        if (ret.msg != 'ok') {
            alertError(ret.msg);
            return ret;
        }
        list = ret.data;
        let arr = [];
        if (list && list.length && !currTerritoryId) {
            let myTerritories = await territories();
            if (myTerritories.msg == 'ok') {
                myTerritories.data.forEach(t => {
                    let tmp = list.find(l => l.name == t.name);
                    if (tmp) {
                        tmp.usedSpacePer = t.totalSpace ? parseInt((100 * t.usedSpace) / t.totalSpace) : 0;
                        // tmp.usedSpacePer = 80;
                        arr.push({ ...t, ...tmp });
                    }
                });
            }
            list = arr;
        }
    } catch (e) {
        console.log(e);
    } finally {
        setIsLoading(false);
        setDirs(list);
        ret.data = list;
        return ret;
    }
}
async function getContainerTree(rootDisabled) {
    let ret = await graphql.getAccountContainers();
    if (ret.msg != 'ok') {
        alertError(ret.msg);
        return ret;
    }
    ret.tree = makeTree(ret.data, rootDisabled);
    return ret;
}
function makeTree(all, rootDisabled) {
    all.forEach(t => {
        t.key = t.id;
        t.title = t.name
    });
    function make(items) {
        for (let item of items) {
            item.children = all.filter((t) => t.parentId == item.id);
            if (item.children.length > 0) {
                make(item.children);
            }
        }
    }
    let tree = all.filter((t) => t.territoryId == null);
    tree.forEach(t => {
        if (rootDisabled) {
            t.disabled = true;
        }
        t.key = "territoryId" + t.id;
        t.children = all.filter(a => a.territoryId == t.id && a.parentId == null);
        if (t.children.length > 0) {
            make(t.children);
        }
    });
    return tree;
}
async function newContainer(currDir, currTerritoryId, newFolderName, setIsLoading) {
    // return console.log(currDir);
    let ret = { msg: 'error' };
    if (!window.isAuthor) {
        antdHelper.alertError("Please authorize");
        return ret;
    }
    let account = oss.getAccount();
    if (!account.balance) {
        antdHelper.alertError("Your balance is 0, Inability to pay the gas");
        return ret;
    }
    let error = valitor.isBucketName(newFolderName);
    if (error) {
        antdHelper.alertError(error);
        return ret;
    }
    setIsLoading(true);
    ret = await graphql.newContainer(newFolderName, currTerritoryId, currDir.id);
    console.log(ret);
    setIsLoading(false);
    if (ret.msg != 'ok') {
        antdHelper.alertError("Create folder fail:" + ret.msg);
    } else {
        antdHelper.notiOK("Create folder success");
    }
    return ret;
}
async function renameContainer(selectItem, newFolderName, setIsLoading) {
    // return console.log(currDir);
    let ret = { msg: 'error' };
    let error = valitor.isBucketName(newFolderName);
    if (error) {
        antdHelper.alertError(error);
        return ret;
    }
    setIsLoading(true);
    ret = await graphql.renameContainer(selectItem.id, newFolderName);
    console.log(ret);
    setIsLoading(false);
    if (ret.msg != 'ok') {
        antdHelper.notiError("Rename folder fail:" + ret.msg);
    }
    antdHelper.notiOK("Rename folder success");
    return ret;
}
async function deleteContainers(selectItems, setIsLoading) {
    setIsLoading(true);
    loading("Loading...");
    let ret;
    for (let selectItem of selectItems) {
        ret = await graphql.deleteContainer(selectItem.id);
        if (ret.msg != 'ok') {
            antdHelper.alertError(ret.msg);
        }
    }
    setIsLoading(false);
    loading();
    return ret;
}

//file
async function fileDeletes(selectItems, setIsLoading) {
    setIsLoading(true);
    loading("Loading...");
    let ret = await fileUpload.deleteFiles(selectItems);
    setIsLoading(false);
    loading();
    return ret;
}
async function fileMove(selectItem, destContainerId, territoryId, setIsLoading) {
    if (!destContainerId || destContainerId == "0") {
        return antdHelper.notiError("Please select the destination folder");
    }
    if (selectItem.containerId == destContainerId) {
        return antdHelper.notiError("The same folder");
    }
    setIsLoading(true);
    let ret = await graphql.updateFileMap(territoryId, selectItem.id, destContainerId);
    setIsLoading(false);
    if (ret.msg != 'ok') {
        antdHelper.notiError(ret.msg);
        return ret;
    }
    antdHelper.notiOK("Move file success");
    return ret;
}
async function fileDetail(fid, shareid) {
    let ret = {}, ret2;
    if (fid) {
        ret2 = await graphql.getMyFiles(null, null, null, fid);
        if (ret2.msg != 'ok' || !ret2.data || ret2.data.length == 0) {
            ret2 = await oss.queryFileMetadata(fid);
            if (ret2.msg != 'ok') {
                antdHelper.alertError(ret2.msg);
                return ret2;
            }
            if (!ret2.data) {
                antdHelper.alertError('File not found');
                return ret2;
            }
            // ret2.data.title = ret2.data?.fileName;
            // ret2.data.fid = fid;
            return ret2;
        }
    } else {
        ret2 = await graphql.getFileMapByShareLink(shareid);
    }
    if (ret2.msg == 'ok' && ret2.data && ret2.data.length) {
        fid = ret2.data[0].fid;
        ret = await oss.queryFileMetadata(fid);
    }
    console.log({ ret, ret2 })
    if (ret.msg == 'ok' && ret2.msg == 'ok' && ret2.data && ret2.data.length) {
        let info = ret2.data[0];
        let data = { ...ret.data, ...info };
        data.fileName = data.title;
        ret.data = data;
    }
    return ret;
}
async function fileSearch(keyword) {
    let ret = await graphql.getMyFiles(null, null, keyword);
    return ret;
}